﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using uTILLIty.Rave.Contract.Schema;

namespace uTILLIty.Rave.Contract.Job
{
  /// <summary>
  /// A job contains all information required to process a directory-template
  /// </summary>
  [XmlRoot(Namespace = WellKnownSchemas.RaveJobConfiguration, IsNullable = false)]
  public class Job
  {
    /// <summary>
    /// Created a default, empty instance
    /// </summary>
    public Job()
    {
      JobId = DateTime.Now.ToString("yyyyMMddHHmmss");
      LogLevel = SourceLevels.Off;
      TemplateEncoding = Properties.Settings.Default.DefaultNVelocityEncoding;
      ValidateAfterMerge = true;
    }

    /// <summary>
    /// Creates a filled-out instance
    /// </summary>
    /// <param name="template"></param>
    /// <param name="mergeVariables"></param>
    public Job(string template, MergeVariable[] mergeVariables)
      : this()
    {
      Template = template;
      MergeVariables = mergeVariables;
    }

    /// <summary>
    /// A unique ID of the job (used during processing - changes on each try of processing the job)
    /// </summary>
    [XmlIgnore]
    public string JobId { get; set; }

    private string _jobSource;

    /// <summary>
    /// The location from which the job was loaded
    /// </summary>
    [XmlIgnore]
    public string JobSource
    {
      get { return _jobSource; }
      set
      {
        _jobSource = !string.IsNullOrWhiteSpace(value) ? new FileInfo(value).FullName : value;
      }
    }

    /// <summary>
    /// The relative or absolute name of the template to process. If relative, the base path configured in the application's settings is used
    /// </summary>
    public string Template { get; set; }

    /// <summary>
    /// Wether to save the (NVelocity) merged template to file
    /// </summary>
    [XmlElement(IsNullable = false), DefaultValue(false)]
    public bool SaveMergedOutput { get; set; }

    /// <summary>
    /// If the LogLevel is not Off, then a logfile is generated with the specified verbosity
    /// </summary>
    [XmlElement(IsNullable = false), DefaultValue(SourceLevels.Off)]
    public SourceLevels LogLevel { get; set; }

    /// <summary>
    /// Used internally by all modules to log all activity to a uniform location
    /// </summary>
    [XmlIgnore]
    public TraceSource TraceSource { get; set; }

    /// <summary>
    /// A list of merge-variables to add to the NVelocity context.
    /// </summary>
    /// <remarks>
    /// Environmental variables are processed. MergeVariables may not be used.
    /// </remarks>
    [XmlArrayItem("Setting", typeof(MergeVariable))]
    [XmlArrayItem("List", typeof(ListMergeVariable))]
    public MergeVariable[] MergeVariables { get; set; }

    /// <summary>
    /// Wether to validate the merged XML before processing/directory-creation
    /// </summary>
    [XmlAttribute("validateAfterMerge"), DefaultValue(true)]
    public bool ValidateAfterMerge { get; set; }

    /// <summary>
    /// The encoding of the <see cref="Template"/>. Default is UTF-8
    /// </summary>
    [XmlAttribute("templateEncoding"), DefaultValue("UTF-8")]
    public string TemplateEncoding { get; set; }

    /// <summary>
    /// Returns the parsed <see cref="TemplateEncoding"/>
    /// </summary>
    /// <exception cref="ArgumentException">Thrown, if the supplied Encoding cannot be resolved/parsed</exception>
    public Encoding GetEncoding()
    {
      return Encoding.GetEncoding(TemplateEncoding);
    }

    /// <summary>
    /// Adds the current <see cref="JobId"/> to the supplied filename.
    /// </summary>
    public virtual string AddJobIdToFilename(string fileName)
    {
      if (fileName.Contains(JobId))
        return fileName;
      return Path.ChangeExtension(fileName, string.Format("{0}{1}", JobId, Path.GetExtension(fileName)));
    }
  }
}